﻿#include "server_asio.h"
#include <iostream>
#include <memory>
#include <boost/bind.hpp>

ServerAsio::ServerAsio()
	: acceptor_(io_context_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 0)) {
	
}

void ServerAsio::Start() {
	read_buffer_.resize(2048);
	PrepareAccept();
	thread_ = std::thread([this]() {
		io_context_.run();
	});
}

void ServerAsio::Stop() {
	io_context_.stop();
}

void ServerAsio::Wait() {
	thread_.join();
}

unsigned short ServerAsio::Port() const {
	return acceptor_.local_endpoint().port();
}

void ServerAsio::PrepareAccept() {
	auto socket = std::make_shared<boost::asio::ip::tcp::socket>(io_context_);
	acceptor_.async_accept(*socket, boost::bind(&ServerAsio::OnAccept, this, boost::asio::placeholders::error, socket));
}

void ServerAsio::OnAccept(boost::system::error_code error, std::shared_ptr<boost::asio::ip::tcp::socket> socket) {
	socket->async_read_some(boost::asio::buffer(read_buffer_), boost::bind(&ServerAsio::OnRead,
		this,
		boost::asio::placeholders::error,
		socket,
		boost::asio::placeholders::bytes_transferred));
}

void ServerAsio::OnRead(boost::system::error_code error, std::shared_ptr<boost::asio::ip::tcp::socket> socket, size_t size) {
	if (!error) {
		write_buffer_.resize(2048);
		write_buffer_.swap(read_buffer_);
		write_buffer_.resize(size);
		socket->async_write_some(boost::asio::buffer(write_buffer_), boost::bind(&ServerAsio::OnWrite,
			this,
			boost::asio::placeholders::error,
			socket,
			boost::asio::placeholders::bytes_transferred));
	}
}

void ServerAsio::OnWrite(boost::system::error_code error, std::shared_ptr<boost::asio::ip::tcp::socket> socket, size_t size) {
	if (!error) {
		socket->async_read_some(boost::asio::buffer(read_buffer_), boost::bind(&ServerAsio::OnRead,
			this,
			boost::asio::placeholders::error,
			socket,
			boost::asio::placeholders::bytes_transferred));
	}
}
